package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"sort"
	"strconv"
	"syscall"
)

type Mind struct {
	number int64
	values map[int][]int64
}

func NewMind(number int64) *Mind {
	return &Mind{
		number: number,
		values: make(map[int][]int64),
	}
}

func (m *Mind) set(s string) {
	rs := m.reverse(s)
	for i := 0; i < len(rs); i++ {
		if _, ok := m.values[i]; !ok {
			m.values[i] = make([]int64, 0)
		}

		if string(rs[i]) == "1" {
			v, _ := strconv.ParseInt(s, 2, 10)
			m.values[i] = append(m.values[i], v)
		}
	}
}

func (m *Mind) convert(i int) string {
	s := ""
	if i == 0 {
		return "0"
	}
	for ; i > 0; i /= 2 {
		s = strconv.Itoa(i%2) + s
	}
	return s
}

func (m *Mind) reverse(s string) string {
	ss := ""
	for i := len(s) - 1; i >= 0; i-- {
		ss = ss + string(s[i])
	}
	return ss
}

func (m *Mind) random(values []int64) []int64 {
	if len(values) <= 0 {
		return values
	}

	maps := make(map[int64]int64)
	for _, v := range values {
		maps[v] = v
	}

	result := make([]int64, 0, len(maps))
	for v := range maps {
		result = append(result, v)
	}

	return result
}

func (m *Mind) sort(values map[int][]int64) [][]int64 {
	keys := make([]int, 0)
	for k := range values {
		keys = append(keys, k)
	}

	sort.Ints(keys)

	result := make([][]int64, 0)
	for _, key := range keys {
		result = append(result, values[key])
	}

	return result
}

func (m *Mind) Get() [][]int64 {
	var i int64 = 1
	for ; i <= m.number; i++ {
		b := m.convert(int(i))
		m.set(b)
	}

	values := make([][]int64, 0)
	for _, v := range m.sort(m.values) {
		values = append(values, m.random(v))
	}

	return values
}

var port, value int

func init() {
	flag.IntVar(&port, "p", 9090, "server port")
	flag.IntVar(&value, "n", 30, "default number")
	flag.Parse()
}

func main() {
	addr := fmt.Sprintf(":%d", port)
	go start(addr)

	fmt.Println("start server", fmt.Sprintf("http://127.0.0.1:%d", port))

	sign := make(chan os.Signal, 1)
	signal.Notify(sign, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGSTOP)

	s := <-sign

	fmt.Println("stop server", s)
}

func start(addr string) {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		n := r.FormValue("n")

		number, err := strconv.ParseInt(n, 10, 64)
		if err != nil || number <= 10 {
			number = int64(value)
		}

		m := NewMind(number)
		body, err := json.Marshal(m.Get())
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(body))
	})

	if err := http.ListenAndServe(addr, mux); err != nil {
		panic(err)
	}
}
